package albert3d.gui;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import com.jogamp.opengl.util.GLBuffers;
import javax.media.opengl.GL3;

public class Shader {

	public int initVertexShader(GL3 gl, String fileName) throws IOException {
		
		String[] vertexShaderSource = loadShaderFile(fileName);
		int vertexShaderObject = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
		gl.glShaderSource(vertexShaderObject, 1, vertexShaderSource, null);
		gl.glCompileShader(vertexShaderObject);
		printShaderLog(gl, vertexShaderObject);
		return vertexShaderObject;
	}

	public int initFragmentShader(GL3 gl, String fileName) throws IOException {
		
		String[] fragmentShaderSource = loadShaderFile(fileName);
		int fragmentShaderObject = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
		gl.glShaderSource(fragmentShaderObject, 1, fragmentShaderSource, null);
		gl.glCompileShader(fragmentShaderObject);
		printShaderLog(gl, fragmentShaderObject);
		return fragmentShaderObject;
	}

	public int initShaderProgram(GL3 gl, int vertexShaderObject, int fragmentShaderObject) {
		int shaderProgramObject = gl.glCreateProgram();
		if (vertexShaderObject != 0)
			gl.glAttachShader(shaderProgramObject, vertexShaderObject);
			
		if (fragmentShaderObject != 0)
			gl.glAttachShader(shaderProgramObject, fragmentShaderObject);
		
		gl.glLinkProgram(shaderProgramObject);
		gl.glValidateProgram(shaderProgramObject);
		printProgramLog(gl, shaderProgramObject);
		return shaderProgramObject;
	}

	private void printShaderLog(GL3 gl, int shader) {
		IntBuffer intBuffer = GLBuffers.newDirectIntBuffer(1);
		gl.glGetShaderiv(shader, GL3.GL_INFO_LOG_LENGTH, intBuffer);
		int infoLength = intBuffer.get(0);
		if (infoLength > 1) {
			ByteBuffer byteBuffer = GLBuffers.newDirectByteBuffer(infoLength);
			gl.glGetShaderInfoLog(shader, infoLength, intBuffer, byteBuffer);
			byteBuffer.rewind();
			byte dst[] = new byte[byteBuffer.capacity()];
			byteBuffer.get(dst, 0, byteBuffer.capacity());
			String message = new String(dst);
			gl.glDeleteShader(shader);
			System.out.println(message);
			throw new IllegalStateException(message);
		}
	}

	private void printProgramLog(GL3 gl, int program) {
		IntBuffer intBuffer = GLBuffers.newDirectIntBuffer(1);
		gl.glGetProgramiv(program, GL3.GL_INFO_LOG_LENGTH, intBuffer);
		int infoLength = intBuffer.get(0);
		if (infoLength > 1) {
			ByteBuffer byteBuffer = GLBuffers.newDirectByteBuffer(infoLength);
			gl.glGetProgramInfoLog(program, infoLength, intBuffer, byteBuffer);
			byteBuffer.rewind();
			byte dst[] = new byte[byteBuffer.capacity()];
			byteBuffer.get(dst, 0, byteBuffer.capacity());
			String message = new String(dst);
			gl.glDeleteProgram(program);
			System.out.println(message);
			throw new IllegalStateException(message);
		}
	}

	public String[] loadShaderFile(String fileName) throws IOException {
		InputStream is = new FileInputStream(new File(fileName));
		StringBuffer sb = new StringBuffer();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String str = null;
		while ((str = br.readLine()) != null) {
			sb.append(str).append('\n');
		}
		String[] result = { sb.toString() };
		is.close();
		br.close();
		return result;
	}

}
